{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 多层感知机概念：\n",
    "- 多层感知机在输入层和输出层之间增加一个或者多个全连接隐藏层，并通过激活函数转换隐藏层的输出\n",
    "- 常用的激活函数包括ReLU（修正线性单元）、sigmoid、tanh、softmax\n",
    "## １、导入包"
   ],
   "id": "767b4a4bb6c01ef"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T08:41:32.547874Z",
     "start_time": "2024-11-08T08:41:30.214887Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import torch\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets, transforms"
   ],
   "id": "cca70fcd2c7f9fc4",
   "outputs": [],
   "execution_count": 1
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 2、小批量获取数据",
   "id": "5a356ae1598b83a3"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T09:16:48.777701Z",
     "start_time": "2024-11-08T09:16:48.666877Z"
    }
   },
   "cell_type": "code",
   "source": [
    "mnist_train = datasets.MNIST('../data',transform=transforms.ToTensor(), train=True)\n",
    "mnist_test = datasets.MNIST('../data',transform=transforms.ToTensor(), train=False)\n",
    "train_loader = DataLoader(mnist_train, batch_size=10,shuffle=True)\n",
    "test_loader = DataLoader(mnist_test, batch_size=10,shuffle=True)"
   ],
   "id": "10a83ce40d39faa1",
   "outputs": [],
   "execution_count": 24
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 3、定义模型(多层感知机)\n",
   "id": "436e059116b461c8"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# H = XW1 + b1 隐藏层变量\n",
    "# O = HW2 + b2 输出函数\n",
    "def net(X):\n",
    "    X = X.reshape(-1, num_inputs)\n",
    "    H = relu(X@w1 + b1)\n",
    "    O = H@w2 + b2\n",
    "    return O"
   ],
   "id": "393d792dc5bfaa2"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 4、初始化参数",
   "id": "ee5f8c4ac13a10c9"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T08:48:35.896135Z",
     "start_time": "2024-11-08T08:48:35.883657Z"
    }
   },
   "cell_type": "code",
   "source": [
    "num_inputs,num_outputs,num_hiddens = 784,10,256\n",
    "w1 = torch.nn.Parameter(torch.randn(num_inputs,num_hiddens,requires_grad=True) * 0.01)\n",
    "b1 = torch.nn.Parameter(torch.zeros(num_hiddens,requires_grad=True))\n",
    "w2 = torch.nn.Parameter(torch.randn(num_hiddens,num_outputs,requires_grad=True) * 0.01)\n",
    "b2 = torch.nn.Parameter(torch.zeros(num_outputs,requires_grad=True))\n",
    "params = [w1,b1,w2,b2]"
   ],
   "id": "b7380b2b914896dc",
   "outputs": [],
   "execution_count": 5
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 5、定义损失函数",
   "id": "52ab76658eaca030"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T08:48:40.586778Z",
     "start_time": "2024-11-08T08:48:40.581292Z"
    }
   },
   "cell_type": "code",
   "source": "loss_fn = torch.nn.CrossEntropyLoss(reduction=\"none\") # 交叉熵",
   "id": "9e82f221fece9624",
   "outputs": [],
   "execution_count": 6
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 6、定义优化函数",
   "id": "6854f154234192e1"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T09:12:40.199297Z",
     "start_time": "2024-11-08T09:12:40.193033Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def updater(params, lr, batch_size):\n",
    "    with torch.no_grad():\n",
    "        for param in params:\n",
    "            # 参数更新公式为，这里除以 batch_size 是因为在一次前向传播中，\n",
    "            # 梯度是对整个批量数据求和的结果，所以需要平均化以确保学习率的一致性。\n",
    "            param -= lr / batch_size * param.grad \n",
    "            param.grad.zero_()\n",
    "            "
   ],
   "id": "de963b49f65413d6",
   "outputs": [],
   "execution_count": 21
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 7、定义激活函数",
   "id": "98e49eb8a816865f"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T09:01:04.514572Z",
     "start_time": "2024-11-08T09:01:04.509171Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#激活函数决定了神经元是否应该被激活（即是否向下一层次传递信息）。\n",
    "# 如果激活函数的输出接近于零，则认为该神经元处于抑制状态；如果输出较大，则认为该神经元被激活。\n",
    "# relu = max(0,a) \n",
    "def relu(X):\n",
    "    a = torch.zeros_like(X)\n",
    "    return torch.max(X,a)"
   ],
   "id": "bab48b6503648e69",
   "outputs": [],
   "execution_count": 13
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "",
   "id": "e1b87c8695f94c46"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 8、训练模型",
   "id": "1e57de4bfeea5629"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T09:13:59.644486Z",
     "start_time": "2024-11-08T09:12:44.650772Z"
    }
   },
   "cell_type": "code",
   "source": [
    "epochs = 10 # 轮数\n",
    "lr = 0.01 # 学习率\n",
    "batch_size = 10 # 批次数\n",
    "for epoch in range(epochs):\n",
    "    for X,y in train_loader:\n",
    "        y_pred = net(X)\n",
    "        loss = loss_fn(y_pred, y)\n",
    "        loss.sum().backward()\n",
    "        updater(params, lr, batch_size)"
   ],
   "id": "f83b72ac5d82a4f",
   "outputs": [],
   "execution_count": 22
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 9、预测数据",
   "id": "44d8b480119964ee"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-08T09:16:52.923352Z",
     "start_time": "2024-11-08T09:16:52.909332Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def get_labels(labels):\n",
    "    text_labels = [\"t-shirt(T恤)\", \"trouser(裤子)\", \"pullover(套衫)\", \"dress(连衣裙)\", \"coat(外套)\", \"sandal(凉鞋)\",\"shirt(衬衫)\", \"sneaker(运动鞋)\",\n",
    "                   \"bag(包)\", \"ankle boot(短靴)\"]\n",
    "    return [text_labels[int(label)] for label in labels ]\n",
    "for X,y in test_loader:\n",
    "    break;\n",
    "trues = get_labels(y)\n",
    "preds = get_labels(net(X).argmax(axis=1))\n",
    "print(trues)\n",
    "print(preds)    "
   ],
   "id": "581efe60b4a2de71",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['shirt(衬衫)', 'sandal(凉鞋)', 'trouser(裤子)', 'dress(连衣裙)', 'sneaker(运动鞋)', 'bag(包)', 't-shirt(T恤)', 'trouser(裤子)', 'trouser(裤子)', 'pullover(套衫)']\n",
      "['shirt(衬衫)', 'sandal(凉鞋)', 'trouser(裤子)', 'dress(连衣裙)', 'sneaker(运动鞋)', 'bag(包)', 't-shirt(T恤)', 'trouser(裤子)', 'trouser(裤子)', 'pullover(套衫)']\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "91a6c874907d98fb"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
